package com.flying.invest.account.service;

import java.util.Date;
import java.util.List;

import org.apache.http.client.utils.DateUtils;

import com.flying.common.annotation.DaoCreate;
import com.flying.common.annotation.DaoQuery;
import com.flying.common.annotation.DaoRemove;
import com.flying.common.annotation.DaoUpdate;
import com.flying.common.annotation.Transaction;
import com.flying.common.util.Codes;
import com.flying.framework.annotation.MethodInfo;
import com.flying.framework.annotation.Param;
import com.flying.framework.annotation.Service;
import com.flying.framework.context.ServiceContext;
import com.flying.framework.model.ActionResult;
import com.flying.framework.model.ModelFactory;
import com.flying.framework.model.QueryResult;
import com.flying.framework.security.Principal;
import com.flying.framework.service.AbstractService;
import com.flying.invest.account.model.Account;
import com.flying.invest.account.model.Account.AccountType;
import com.flying.invest.account.model.AccountFlow;
import com.flying.invest.base.service.CurrencyService;
import com.flying.invest.invest.TransactionType;

@Service(value="AccountService", desc="现金账户")
public class AccountService extends AbstractService{
	private AccountFlowService afs;
    private CurrencyService cs;
    private AccountNetValueService anvs;
	
	public void setAccountFlowService(AccountFlowService s) {
		this.afs = s;
	}
    public void setCurrencyService(CurrencyService s) {
    	this.cs = s;
    }
    public void setAccountNetValueService(AccountNetValueService s) {
    	this.anvs = s;
    }
        
	@MethodInfo("新增")
	@DaoCreate(entity=Account.ENTITY_NAME)
	public Account create(
		
			@Param(value=Account.USER_ID, required=false,	desc="所属用户") Long user_id,
			@Param(value=Account.NAME, required=true,	desc="名称") String name,
			@Param(value=Account.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=Account.ACCOUNT_TYPE, required=true,	desc="账户类型", enumClass = AccountType.class) Integer account_type,
			@Param(value=Account.CURRENCY, required=true,	desc="币种") String currency,
			@Param(value=Account.CREATOR, required=false,	desc="创建人") String creator,
			@Param(value=Account.CREATE_TIME, required=false,	desc="创建时间") Date create_time
		
		) throws Exception {
		
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(Account.class, 
				Account.USER_ID, user_id == null?Long.parseLong(p.getId()): user_id,
				Account.CREATOR, (p == null?null: p.getName()),
				Account.CREATE_TIME, new Date());
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=Account.ENTITY_NAME)
	public ActionResult update(
		
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id,
			@Param(value=Account.NAME, required=true,	desc="名称") String name,
			@Param(value=Account.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=Account.UPDATOR, required=false,	desc="修改人") String updator,
			@Param(value=Account.UPDATE_TIME, required=false,	desc="修改时间") Date update_time
			
		) throws Exception {
		
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(ActionResult.class, 
				Account.UPDATOR, (p == null?null: p.getName()),
				Account.UPDATE_TIME, new Date());
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=Account.ENTITY_NAME)
	protected ActionResult updateAmount(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id,
			@Param(value=Account.AMOUNT, required=false,	desc="余额") Double amount,
			@Param(value=Account.UPDATOR, required=false,	desc="修改人") String updator,
			@Param(value=Account.UPDATE_TIME, required=false,	desc="修改时间") Date update_time
		) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(ActionResult.class, 
				Account.UPDATOR, (p == null?null: p.getName()),
				Account.UPDATE_TIME, new Date());
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=Account.ENTITY_NAME)
	protected ActionResult updateAmountWithShares(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id,
			@Param(value=Account.AMOUNT, required=false,	desc="余额") Double amount,
			@Param(value=Account.SHARES, required=false,	desc="份额") Double shares,
			@Param(value=Account.UPDATOR, required=false,	desc="修改人") String updator,
			@Param(value=Account.UPDATE_TIME, required=false,	desc="修改时间") Date update_time
		) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(ActionResult.class, 
				Account.UPDATOR, (p == null?null: p.getName()),
				Account.UPDATE_TIME, new Date());
	}

	@MethodInfo("修改")
	@Transaction
	public ActionResult charge(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id,
			@Param(value=Account.AMOUNT, required=true, min="0",	desc="余额") Double amount,
			@Param(value=AccountFlow.REMARKS, required=false,	desc="说明") String remarks
		) throws Exception {
		Account a = this.findById(account_id);
		if(a.getAmount() == null) a.setAmount(0.0);
		Double netValue = a.getNetValue() == null?1.0: a.getNetValue();
		Double shares = a.getShares() == null?0.0: a.getShares();
		this.afs.create(a.getUserId(), account_id, amount, TransactionType.BUY.value, new Date(), null, remarks, new Date());
		return this.updateAmountWithShares(account_id, a.getAmount() + amount, shares + amount / netValue, null, null);
	}

	@MethodInfo("修改")
	@Transaction
	public ActionResult withdraw(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id,
			@Param(value=Account.AMOUNT, required=true, min="0",	desc="余额") Double amount,
			@Param(value=AccountFlow.REMARKS, required=false,	desc="说明") String remarks
		) throws Exception {
		Account a = this.findById(account_id);
		if(a.getAmount() == null) a.setAmount(0.0);
		Double netValue = a.getNetValue() == null?1.0: a.getNetValue();
		Double shares = a.getShares() == null?0.0: a.getShares();
		this.afs.create(a.getUserId(), account_id, amount, TransactionType.SELL.value, new Date(), null, remarks, new Date());
		return this.updateAmountWithShares(account_id, a.getAmount() - amount, shares - amount / netValue, null, null);
	}

	@MethodInfo("修改")
	@Transaction
	public ActionResult transfermOutForBuy(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id,
			@Param(value=Account.AMOUNT, required=true, min="0",	desc="余额") Double amount,
			@Param(value=AccountFlow.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=AccountFlow.TRANSACTION_ID, required=false,	desc="交易时间") Long transaction_id
		) throws Exception {
		Account a = this.findById(account_id);
		if(a.getAmount() == null) a.setAmount(0.0);
		this.afs.create(a.getUserId(), account_id, amount, TransactionType.SELL.value, new Date(), transaction_id, remarks, new Date());
		return this.updateAmount(account_id, a.getAmount() - amount, null, null);
	}

	@MethodInfo("修改")
	@Transaction
	public ActionResult transfermInForSell(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id,
			@Param(value=Account.AMOUNT, required=true, min="0",	desc="余额") Double amount,
			@Param(value=AccountFlow.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=AccountFlow.TRANSACTION_ID, required=false,	desc="交易时间") Long transaction_id
		) throws Exception {
		Account a = this.findById(account_id);
		if(a.getAmount() == null) a.setAmount(0.0);
		this.afs.create(a.getUserId(), account_id, amount, TransactionType.BUY.value, new Date(), transaction_id, remarks, new Date());
		return this.updateAmount(account_id, a.getAmount() + amount, null, null);
	}

	@MethodInfo("删除")
	@DaoRemove(entity=Account.ENTITY_NAME)
	public ActionResult remove(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id
		) throws Exception {
		return null;
	}

	@SuppressWarnings("unchecked")
	@MethodInfo("搜索")
	@DaoQuery(entity=Account.ENTITY_NAME, pageable=true, modelClass=Account.class)
	public QueryResult<Account> findAll(
			@Param(value=Account.USER_ID, required=false,	desc="所属用户") Long user_id,
			@Param(value=Codes.PAGE_NUM, 	required=false, desc="分页页号，默认0") int page,
			@Param(value=Codes.PAGE_SIZE, 	required=false, desc="分页大小，默认10") int rows) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null) user_id = Long.parseLong(p.getId());
		return ModelFactory.create(QueryResult.class, Account.USER_ID, user_id);
	}
	
	//
	@MethodInfo("修改")
	@Transaction
	public ActionResult updateNetValueByUserId(
			@Param(value=Account.USER_ID, required=false,	desc="所属用户") Long user_id
		) {
		List<Account> list = this.findForTotalAmount(user_id).getRows();
		list.stream().forEach(account -> {
			var account_id = account.getAccountId();
			var shares = account.getShares() == null?0.0: account.getShares();
			var total_amount = account.getTotalAmount();
			var account_date = DateUtils.formatDate(new Date(), "yyyy-MM-dd");
			var net_value = shares > 0?total_amount / shares: 1.0;
			this.anvs.remove(account_id, account_date);
			this.anvs.create(account.getUserId(), account_id, account_date, net_value, shares, total_amount, new Date());
			this.updateTotalAmountAndNetValue(account_id, total_amount, net_value);
		});
		return ModelFactory.create(ActionResult.class, Codes.CODE, Codes.SUCCESS);
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=Account.ENTITY_NAME)
	protected ActionResult updateTotalAmountAndNetValue(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id,
			@Param(value=Account.TOTAL_AMOUNT, required=false,	desc="总额") Double total_amount,
			@Param(value=Account.NET_VALUE, required=false,	desc="总额") Double net_value
		) {
		return null;
	}

	@SuppressWarnings("unchecked")
	@MethodInfo("搜索")
	@DaoQuery(entity=Account.ENTITY_NAME, pageable=false, modelClass=Account.class, qsql="SELECT * FROM v_account_cost t")
	protected QueryResult<Account> findForTotalAmount(
			@Param(value=Account.USER_ID, required=true,	desc="所属用户") Long user_id) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null) user_id = Long.parseLong(p.getId());
		return ModelFactory.create(QueryResult.class, Account.USER_ID, user_id);
	}
	
	//
	@MethodInfo("查询")
	@DaoQuery(entity=Account.ENTITY_NAME, single=true, throwsNotFoundException=true )
	public Account findById(
			@Param(value=Account.ACCOUNT_ID, required=true,	desc="账户ID") Long account_id
		) throws Exception {
		return null;
	}

	public Double summary(
			@Param(value=Account.USER_ID, required=false,	desc="所属用户") Long user_id) {
		List<Account> accounts = this.findAll(user_id, 0, Integer.MAX_VALUE).getRows();
		Double summary = 0.0;
		for(Account a: accounts) {
			Double amount = a.getAmount() == null?0.0:a.getAmount();
			if("CNY".equalsIgnoreCase(a.getCurrency())) {
				summary += amount;
			} else {
				Double rate = this.cs.findByCode(a.getCurrency()).getRate();
				summary += amount * rate;
			}
		}
		return summary;
	}
}